#include "file_utils.h"
#include "elog.h"
#include "elog_file.h"

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <iostream>
#include <algorithm>
#include <filesystem>
#include <sstream>
#include <iomanip>

namespace fs = std::filesystem;

// 检查文件名称是否包含指定的前缀字符串
bool startsWith(const std::string& str, const std::string& prefix) {
    if (prefix.length() > str.length()) {
        return false;
    }

    return std::equal(prefix.begin(), prefix.end(), str.begin());
}

// 辅助函数，检查文件夹名称是否包含指定的字符串列表中的任意字符串
bool containsAny(const std::string& dirname, const std::vector<std::string>& substrings) {
    return std::any_of(substrings.begin(), substrings.end(),
                       [&](const std::string& substring) { return dirname.find(substring) != std::string::npos; });
}

// 获取指定文件夹内带有指定扩展名的文件数量
int countFilesWithExtension(const std::string& folder, const std::string& extension) {
    int count = 0;

    try {
        for (const auto& entry : fs::directory_iterator(folder)) {
            if (entry.is_regular_file() && entry.path().extension() == extension) {
                count++;
            }
        }
    } catch (const fs::filesystem_error& ex) {
        std::cerr << "Error counting files: " << ex.what() << std::endl;
    }

    return count;
}

// 从源目录（src_dir）中移动带有指定前缀（prefix）和指定扩展名（extension）的文件到目标目录（dest_dir）中
void moveFilesWithPrefixAndExtension(const std::string& src_dir, const std::string& dest_dir, const std::string& prefix, const std::string& extension) {
    try {
        for (const auto& entry : fs::directory_iterator(src_dir)) {
            if (entry.is_regular_file()) {
                const std::string& filename = entry.path().filename().string();
                if (startsWith(filename, prefix) && entry.path().extension() == extension) {
                    // 获取目标路径
                    std::string dest_path = dest_dir + "/" + filename;

                    // 移动文件
                    fs::rename(entry.path(), dest_path);
                    log_i("Moved file: %s", filename.c_str());
                }
            }
        }
    } catch (const fs::filesystem_error& ex) {
        log_e("Error moving files: %s", ex.what());
    }
}


void moveDirectoriesWithPrefixAndExclusion(const std::string& src_dir, const std::string& dest_dir, 
                                          const std::string& prefix, const std::vector<std::string>& exclusions) {
    try {
        // 创建目标文件夹
        fs::create_directory(dest_dir);

        for (const auto& entry : fs::directory_iterator(src_dir)) {
            if (entry.is_directory()) {
                // 获取源文件夹名称
                const std::string& dirname = entry.path().filename().string();

                if (startsWith(dirname, prefix) && !containsAny(dirname, exclusions)) {
                    // 获取源文件夹路径
                    std::string src_subdir_path = entry.path().string();

                    // 获取目标文件夹路径
                    std::string dest_subdir_path = dest_dir + "/" + dirname;

                    // 移动当前文件夹
                    fs::rename(entry.path(), dest_subdir_path);
                    log_i("Moved directory: %s", dirname.c_str());
                }
            }
        }
    } catch (const fs::filesystem_error& ex) {
        log_e("Error moving directories: %s", ex.what());
    }
}


void moveDirectoriesWithPrefix(const std::string& src_dir, const std::string& dest_dir, const std::string& prefix) {
    try {
        // 创建目标文件夹
        fs::create_directory(dest_dir);

        for (const auto& entry : fs::directory_iterator(src_dir)) {
            if (entry.is_directory()) {
                // 获取源文件夹名称
                const std::string& dirname = entry.path().filename().string();

                if (startsWith(dirname, prefix)) {
                    // 获取源文件夹路径
                    std::string src_subdir_path = entry.path().string();

                    // 获取目标文件夹路径
                    std::string dest_subdir_path = dest_dir + "/" + dirname;

                    // 移动当前文件夹
                    fs::rename(entry.path(), dest_subdir_path);
                    log_i("Moved directory: %s", dirname.c_str());
                }
            } 
        }
    } catch (const fs::filesystem_error& ex) {
        log_e("Error moving directories: %s", ex.what());
    }
}

void deleteDirectoriesWithPrefix(const std::string& src_dir, const std::string& prefix) {
    try {
        for (const auto& entry : fs::directory_iterator(src_dir)) {
            if (entry.is_directory()) {
                // 获取源文件夹名称
                const std::string& dirname = entry.path().filename().string();

                if (startsWith(dirname, prefix)) {
                    // 获取源文件夹路径
                    std::string src_subdir_path = entry.path().string();

                    // 移动当前文件夹
                    fs::remove_all(src_subdir_path);
                    log_i("Deleted directory: %s", dirname.c_str());
                }
            }
        }
    } catch (const fs::filesystem_error& ex) {
        log_e("Error deleting directories: %s", ex.what());
    }
}

// 获取文件大小，字符串形式返回
std::string getFileSizeString(const std::string& file_path) {
    try {
        std::uintmax_t file_size = fs::file_size(file_path);
        std::ostringstream oss;

        if (file_size < 1024) {
            oss << file_size << " B";
        } else if (file_size < 1024 * 1024) {
            oss << std::fixed << std::setprecision(2) << static_cast<double>(file_size) / 1024 << " KB";
        } else if (file_size < 1024 * 1024 * 1024) {
            oss << std::fixed << std::setprecision(2) << static_cast<double>(file_size) / (1024 * 1024) << " MB";
        } else {
            oss << std::fixed << std::setprecision(2) << static_cast<double>(file_size) / (1024 * 1024 * 1024) << " GB";
        }

        return oss.str();
    } catch (const std::filesystem::filesystem_error& ex) {
        log_e("can not get file size: %s", ex.what());

        return "unknown";
    }
}

// 获取文件大小，int64形式返回
int64_t getFileSizeInt(const std::string& file_path) {
    try {
        std::uintmax_t file_size = fs::file_size(file_path);
        return file_size;
    } catch (const std::filesystem::filesystem_error& ex) {
        log_e("can not get file size: %s", ex.what());

        return 0;
    }
}

int64_t getFileSizeIntUsingStat64(const std::string& file_path) {
    struct stat64 stat_buf;
    if (stat64(file_path.c_str(), &stat_buf) != 0) {
        log_e("Failed to get file stats");
        return 0;
    }
    log_i("get file size = %ld", static_cast<int64_t>(stat_buf.st_size));

    return static_cast<int64_t>(stat_buf.st_size);
}

// 获取文件的修改时间
std::time_t getFileModifiedTime(const std::string& file_path) {
    try {
        fs::file_time_type modified_time = fs::last_write_time(file_path);
        return std::chrono::system_clock::to_time_t(modified_time);
    } catch (const std::filesystem::filesystem_error& ex) {
        log_e("can not get file modified time: %s", ex.what());
        return 0;
    }
}

std::time_t getFileModifiedTimeUsingStat64(const std::string& file_path) {
    struct stat64 stat_buf;
    if (stat64(file_path.c_str(), &stat_buf) != 0) {
        log_e("Failed to get file stats");
        return 0;
    }

    return stat_buf.st_mtime;
}

bool deleteFile(const std::string& file_path) {
    try {
        if (fs::remove(file_path)) {
            log_e("delete file successfully");
            return true;
        } else {
            log_e("delete file failed");
            return false;
        }
    } catch (const std::filesystem::filesystem_error& ex) {
        log_e("can not delete file: %s", ex.what());
        return false;
    }
}

bool deleteFolder(const std::string& folder_path) {
    try {
        if (fs::remove_all(folder_path)) {
            log_e("delete folder successfully");
            return true;
        } else {
            log_e("delete folder failed");
            return false;
        }
    } catch (const std::filesystem::filesystem_error& ex) {
        log_e("can not delete folder: %s", ex.what());
        return false;
    }
}

bool renameFile(const std::string& old_file_path, const std::string& new_file_path) {
    try {
        fs::rename(old_file_path, new_file_path);
        return true;
    } catch (const std::filesystem::filesystem_error& ex) {
        log_e("can not rename file: %s", ex.what());
        return false;
    }
}

// 从文件路径中提取倒数第n个路径分隔符之前的部分作为文件夹路径
std::string extractFolderPath(const std::string& file_path, size_t n) {
    size_t separatorPos = std::string::npos;
    
    // 找到倒数第 n 个路径分隔符的位置
    for (size_t i = 0; i < n; ++i) {
        separatorPos = file_path.find_last_of("/\\", separatorPos - 1);
        
        // 如果找不到足够的分隔符，返回空字符串
        if (separatorPos == std::string::npos) {
            return "";
        }
    }
    
    // 提取文件夹路径
    return file_path.substr(0, separatorPos);
}

// 判断文件路径是否包含指定的字符串
bool isPathContains(const std::string& file_path, const std::string& target_str) {
    // 使用find函数查找目标字符串
    return file_path.find(target_str) != std::string::npos;
}

// 获取文件扩展名
std::string getFileExtension(const std::string& filePath) {
    size_t dotPos = filePath.find_last_of('.');
    
    if (dotPos != std::string::npos) {
        // 提取扩展名部分，包括点字符
        return filePath.substr(dotPos);
    }
    
    return "";
}

// 获取文件名称
std::string getFileName(const std::string& filePath) {
    size_t slashPos = filePath.find_last_of('/');
    
    if (slashPos != std::string::npos) {
        // 提取文件名部分，不包括路径分隔符
        return filePath.substr(slashPos + 1);
    }
    
    return "";
}

// 获取指定文件夹内带有指定扩展名的第一个文件路径
std::string getFirstFileWithExtension(const std::string& folder, const std::string& extension) {
    try {
        for (const auto& entry : fs::directory_iterator(folder)) {
            if (entry.is_regular_file() && entry.path().extension() == extension) {
                return entry.path().string();
            }
        }
    } catch (const fs::filesystem_error& ex) {
        std::cerr << "Error finding the first file: " << ex.what() << std::endl;
    }

    return "";
}

// 提取文件路径中倒数第n个文件夹的名称
std::string extractNthFolderName(const std::string& file_path, size_t n) {
    size_t separatorPos = std::string::npos;

    for (size_t i = 0; i < n; ++i) {
        separatorPos = file_path.find_last_of("/\\", separatorPos - 1);

        if (separatorPos == std::string::npos) {
            return "";
        }
    }

    size_t previousSeparatorPos = file_path.find_last_of("/\\", separatorPos - 1);

    if (previousSeparatorPos == std::string::npos) {
        return "";
    }

    return file_path.substr(previousSeparatorPos + 1, separatorPos - previousSeparatorPos - 1);
}

int fileSync() {
    system("sync");

    return 0;
}

// 获取指定文件夹内带有指定扩展名的文件总大小
int64_t getTotalSizeOfFilesWithExtension(const std::string& folder, const std::string& extension) {
    int64_t total_size = 0;

    try {
        for (const auto& entry : fs::directory_iterator(folder)) {
            if (entry.is_regular_file() && entry.path().extension() == extension) {
                total_size += fs::file_size(entry);
            }
        }
    } catch (const fs::filesystem_error& ex) {
        std::cerr << "Error calculating total size: " << ex.what() << std::endl;
    }

    return total_size;
}

